package eightDataType;

/**
 * @author Ajie
 * @date 2021/11/5
 * @function 奇偶校验码(Parity Code) Java代码实现
 * https://blog.csdn.net/u013632755/article/details/113813493
 *
 * 奇校验
 * 数据位，校验位，之和为 奇数
 * 偶校验
 * 偶校验英文简写EVEN，当实际数据中“1”的个数为偶数的时候，这个校验位就是“0”，否则这个校验位就是“1”.
 */
public class EvenOddParityCheck {
    public static void main(String[] args) {
        String bs1 = "";
//        byte b1 = (byte) Integer.parseInt(bs1, 2);
//        byte[] checkBytes = new byte[]{b1};
        byte[] checkBytes = {0x00,0x04,0x01};
        checkBytes = new byte[]{ 0x01, 0x05, 0x00, 0x02, (byte) 0xFF, 0x00, (byte) 0x2D, (byte) 0xFA};
        checkBytes = appendEvenNumber(checkBytes);
        bs1 = Integer.toBinaryString(Integer.parseInt(BytesHexStrTranslate.bytesToHexFun1(checkBytes)));
        System.out.println("校验码：" + bs1 + " 奇校验：" + oddNumberCheck(checkBytes, false)); //奇数校验
        System.out.println("校验码：" + bs1 + " 偶校验：" + evenNumberCheck(checkBytes, false)); //偶数校验
    }

    private static byte[] appendEvenNumber(byte[] checkBytes) {
        byte checkMask = 0x1;
        int oddSum = 0;
        for (byte checkByte : checkBytes) {
           oddSum = oddSum + hammingWeight(checkByte);
            System.out.println("1 num:"+oddSum);
        }

        byte makeCheckMask = (byte) (oddSum & checkMask);
        System.out.println("makeCheckMask:"+makeCheckMask);
        byte[] bytes = new byte[checkBytes.length + 1];
        for (int i = 0; i < bytes.length; i++) {
            if (i==bytes.length-1){
                bytes[i]=makeCheckMask;
            }else {
                bytes[i] = checkBytes[i];
            }
        }
        return bytes;
    }
    /**
     *   n = n & (n - 1);//消掉末端的1
     * //eg: 100100
     * //-1: 100011  //之前为1的数为了0，消掉1个1。
     * @param n
     * @return
     */
    public static int hammingWeight(int n) {
        int count = 0;
        while (n != 0) {
            count++;
            //eg: 3  00011
            //    2  00010
            //res:   00010
            //第二次  00001
            //res: 0
            //eg: 100100
            //-1: 100011  //之前为1的数为了0，消掉1个1。
            n = n & (n - 1);// n-1 .
        }
        return count;
    }

    /**
     * 偶校验
     *
     * @param checkBytes 需要检查的字节数组
     * @param full       checkBytes的所有字节累计进行奇偶校验 。true-所有；false-只要有一个字节不通过奇偶校验就直接返回false。
     * @return 是否校验通过
     */
    public static boolean evenNumberCheck(byte[] checkBytes, boolean full) {
        return parityCheck(checkBytes, false, full);
    }

    /**
     * 奇校验
     *
     * @param checkBytes 需要检查的字节数组
     * @param full       checkBytes的所有字节累计进行奇偶校验 。true-所有；false-只要有一个字节不通过奇偶校验就直接返回false。
     * @return 是否校验通过
     */
    public static boolean oddNumberCheck(byte[] checkBytes, boolean full) {
        return parityCheck(checkBytes, true, full);
    }

    /**
     * 奇偶校验
     *
     * @param checkBytes 需要检查的字节数组
     * @param odd        是否奇校验。true-校验，false-偶校验
     * @param full       checkBytes的所有字节累计进行奇偶校验 。true-所有；false-只要有一个字节不通过奇偶校验就直接返回false。
     * @return 是否校验通过
     */
    public static boolean parityCheck(byte[] checkBytes, boolean odd, boolean full) {
        byte checkMask = 0x1;
        int oddSum = 0;
//        System.out.println("checkBytes.length:"+checkBytes.length);
        int byteSize = 8;//
        for (byte checkByte : checkBytes) {
//            System.out.println("checkByte:"+Integer.toBinaryString(checkByte));
            for (int i = 0; i < byteSize; i++) {
                if ((checkByte >> i & checkMask) == 1) {
                    oddSum++;
                }
            }
            if (!full) {
                if (!(odd == isOdd(oddSum))) {
                    return false;
                }
                oddSum = 0;
            }
        }
        return !full || odd == isOdd(oddSum);
    }

    /**
     * 判断传入的整数是否为奇数
     *
     * @param checkInt 校验整数
     * @return true-奇数；false-偶数
     */
    public static boolean isOdd(long checkInt) {
        boolean isOddNumber = false;
        byte checkMask = 0x1;
        if ((checkInt & checkMask) == 1) {//通过校验最后一位是否为1，来判断是否为奇数。
            //为1的bit位数量为奇数
            isOddNumber = true;
        }
        return isOddNumber;
    }


}
